package com.yans.managers
{
	import com.yans.interfaces.ICacheManager;
	
	import flash.events.NetStatusEvent;
	import flash.events.TimerEvent;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.system.Security;
	import flash.system.SecurityPanel;
	import flash.utils.ByteArray;
	import flash.utils.Timer;

	public class CacheManager implements ICacheManager
	{ 
		public function CacheManager() { 
			init();
		}
		
		private const NEEDSPACE:int = 31457280;
		private var _canCache:Boolean;
		
		private var _version:int;
		private var _fileList:Array; 
		private var _sharedObject:SharedObject;
		private var _saveList:Array;
		
		private var _saveTimer:Timer;
		private var _totalTryTime:int = 3;
		private var _tryTime:int = 0;
		 
		public function init():void { 
			_version = -1; 
			_saveTimer = new Timer(500);
			_saveTimer.addEventListener(TimerEvent.TIMER, onTimerHandler);
			_tryTime = 0;
			_canCache = false;
//			_noTip = false;
			getCacheList(); 
			_saveList = []; 
		}
		
		public function getCacheList() : void {
			var t:Array;
			try {
				_sharedObject = SharedObject.getLocal("cyfx/cyfxCache");
				_sharedObject.addEventListener(NetStatusEvent.NET_STATUS, netStausChanged);
				t = _sharedObject.data["fileList"]; 
				if (t == null) {
					_fileList = [];
					_version = -1;
					_canCache = false;
				}
				else { 
					_fileList = t;
					_version = int(_sharedObject.data["version"]);
					_canCache = true;
					_saveTimer.start();
				}
			}
			catch (e:Error) {
				trace(e.message);
			}

			return;
		}
		
		public function get canCache():Boolean {
			return _canCache;
		}
		
		public function setCanCache(canCache:Boolean):void {
			_canCache = canCache;
		}
		
		public function saveCacheList() : Boolean
		{
			var state:String;
			if (!_canCache)
			{
				return false;
			}
			try
			{
				state = _sharedObject.flush(NEEDSPACE);
				if (state != SharedObjectFlushStatus.PENDING)
				{
					_sharedObject.data["fileList"] = _fileList;
					_sharedObject.data["version"] = _version;
					_saveTimer.start();
					return true;
				}
			}
			catch (e:Error)
			{
				Security.showSettings(SecurityPanel.LOCAL_STORAGE);
			}
			return false;
		}
		
		private function netStausChanged(e:NetStatusEvent):void {
			
			_tryTime++;
			if (e.info.code == "SharedObject.Flush.Failed") {
				if (_tryTime < _totalTryTime) {
					//					_noTip = true;
					clearSaveObjects();
					_saveTimer.stop();
				}
				else {
					_canCache = false;
					//					_noTip = true;
					clearSaveObjects();
					_saveTimer.stop();
				}
			}
			else {
				//				_noTip = false;
				_canCache = true;
				_sharedObject.data["fileList"] = _fileList;
				_sharedObject.data["version"] = _version;
				_saveTimer.start();
			} 
		}
		
		private function onTimerHandler(e:TimerEvent):void {
			
			var o:Object;
			var path:String;
			var so:SharedObject; 
			if (!_canCache) {
				return;
			}
			if (_saveList.length > 0) {
				try {
					o = _saveList.splice(0, 1)[0];
					path = o["path"];
					so = SharedObject.getLocal(path);
					so.data[path] = o["data"];
					o = null;
					_sharedObject.data["fileList"] = _fileList;
					_sharedObject.data["version"] = _version;
				}
				catch (e:Error) {
					trace(e);
				}
			}
		}
		
		public function clearSaveObjects() : void { 
			var i:int = _fileList.length;
			while(i--) {
				try {
					SharedObject.getLocal(_fileList[i]).clear();
				} 
				catch(error:Error) {
					trace(error);
				}
			}
			
			_sharedObject.data["version"] = -1;
			_fileList.length = 0;
			_saveList.length = 0;
			return;
		}

		private function deleteFiles(path:String):void {
			var i:int;
			i = _fileList.indexOf(path);
			if(i != -1) _fileList.splice(i, 1);
			
			try {
				SharedObject.getLocal(path).clear();
			} 
			catch(error:Error) {
				trace(error);
			}
		}
		
		public function set(path:String, data:ByteArray, backup:Boolean = true):void { 
			var t:ByteArray; 
			var backup:* = backup;
			if (_fileList == null || _sharedObject == null) {
				return;
			}
			//			path = getPathWithoutSite(path);
			addToFileList(path);
			try {
				if (backup) {
					t = new ByteArray();
					data.position = 0;
					data.readBytes(t, 0, data.length);
					_saveList.push({path:path, data:t});
				}
				else {
					_saveList.push({path:path, data:data});
				}
			}
			catch (e:Error) {
				trace(e.message);
			}
		}
		
		public function get(path:String, callBack:Function, backup:Boolean):void { 
			var t:ByteArray;
			var so:SharedObject;
			var tt:ByteArray;
			if (_fileList == null || _sharedObject == null || !_canCache) {
				trace("#木有缓存", path);
				callBack(null);
				return;
			}
//			path = getPathWithoutSite(path);
			if (_fileList.indexOf(path) == -1) {
				trace("#木有缓存", path);
				callBack(null);
				return;
			}
			
			for(var i:int = 0; i < _saveList.length; i++) {
				if(_saveList[i] == path) {
					t = _saveList[i]["data"];
					break;
				}
			}
			
			if (!t) {
				try {  
					so = SharedObject.getLocal(path);
					t = so.data[path];
					so = null;
				}
				catch (e:Error) {
					trace(e.message);
				}
			}
			if (t) {
				if (backup) {
					tt = new ByteArray();
					t.position = 0;
					t.readBytes(tt, 0, t.length);
					callBack(tt);
					t = null;
				}
				else {
					trace("#有缓存", path);
					callBack(t);
				}
			}
			else {
				trace("#木有缓存", path);
				callBack(null);
			}
		}
		
		private function addToFileList(path:String) : void { 
			trace("#缓入缓存", path);
			var n:int = _fileList.indexOf(path);
			if (n == -1) {
				_fileList.push(path);
			}
		}
	}
}